package com.klun.concTrueWar.five;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * （不推荐）
 * 使用 hashmap 和同步机制来初始化缓存
 * 创建一个 computable 包装器
 * @param <A>
 * @param <V>
 */
public interface Computable<A,V> {
    V compute(A arg) throws InterruptedException;
}

/**
 * 实现计算功能的类
 */
class ExpensiveFunction implements Computable<String,BigInteger>{

    @Override
    public BigInteger compute(String arg) throws InterruptedException {
        // 假设此处进行了长时间的计算
        return new BigInteger(arg);
    }
}

/**
 * 负责记忆的类
 * @param <A>
 * @param <V>
 */
class Memoizer<A,V> implements Computable<A,V>{

    // 此处用hashmap做缓存
    private final Map<A,V> cache = new HashMap<>();
    private final Computable<A,V> c;

    Memoizer(Computable<A, V> c) {
        this.c = c;
    }

    /**
     * Memoizer 采用保守的方法synchronized 对整个compute方法进行同步
     * 每次只能有一个线程能够执行compute方法
     *
     * @param arg
     * @return
     * @throws InterruptedException
     */

    @Override
    public synchronized V compute(A arg) throws InterruptedException {
        V result = cache.get(arg);
        if(result == null){
            // ??? 此处方法是调用的哪个？ compute：计算
            // 可能在这耗费过长的时间
            result = c.compute(arg);
            cache.put(arg,result);
        }
        return result;
    }
}

/**
 * 基于 FutureTask 的 Memoizing 封装器 （几乎完美！！）
 * @param <A>
 * @param <V>
 */
class Memoizer3<A,V> implements Computable<A,V>{

    // 创建的线程安全的 ConcurrentHashMap
    private final Map<A,Future<V>> cache = new ConcurrentHashMap<>();
    private final Computable<A,V> c;

    public Memoizer3(Computable<A, V> c) {
        this.c = c;
    }

    @Override
    public V compute(final A arg) throws InterruptedException {
        Future<V> f = cache.get(arg);
        if(f == null){
            // 开启了一个线程进行计算
            Callable<V> eval = new Callable<V>() {
                @Override
                public V call() throws Exception {
                    return c.compute(arg);
                }
            };
            FutureTask<V> ft = new FutureTask<V>(eval);
            f = ft;
            cache.put(arg,ft);
            ft.run(); //在这里将调用 c.compute
        }
        try {
            return f.get();
        }catch (ExecutionException e){
        }
        return null;
    }
}

/**
 *  最终实现
 * @param <A>
 * @param <V>
 */
class MemoizerLast<A,V> implements Computable<A,V>{
    private final Map<A,Future<V>> cache = new ConcurrentHashMap<>();
    private final Computable<A,V> c;

    public MemoizerLast(Computable<A, V> c) {
        this.c = c;
    }

    @Override
    public V compute(A arg) throws InterruptedException {

        while (true){
            Future<V> f = cache.get(arg);
            if (f == null){
                // 开启了一个线程进行计算
                Callable<V> eval = new Callable<V>() {
                    @Override
                    public V call() throws Exception {
                        return c.compute(arg);
                    }
                };
                FutureTask<V> ft = new FutureTask<V>(eval);
                // Absent:缺席的 此处的判断是同步的
                f = cache.putIfAbsent(arg,ft);
                if(f == null){
                    f = ft;
                    ft.run();
                }
            }
            try {
                return f.get();
            } catch (CancellationException e) {
                // 如果出现异常则移除 future 防止一直得到错误的结果
                cache.remove(arg,f);
            } catch (ExecutionException e){

            }
        }
    }
}






